package server

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"time"

	config "gitcode.com/happy-mj/happy-config"
	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// AmapWeatherResponse 高德天气查询响应结构体（适配API返回格式）
type AmapWeatherResponse struct {
	Status   string     `json:"status"`   // 状态码：1=成功，0=失败
	Info     string     `json:"info"`     // 状态信息
	Infocode string     `json:"infocode"` // 状态码说明（10000=成功）
	Count    string     `json:"count"`    // 返回结果总数
	Lives    []struct { // 实况天气数据（extensions=base时返回）
		Province      string `json:"province"`      // 省份名
		City          string `json:"city"`          // 城市名
		Adcode        string `json:"adcode"`        // 区域编码
		Weather       string `json:"weather"`       // 天气现象（如：晴、阴）
		Temperature   string `json:"temperature"`   // 实时气温（℃）
		Winddirection string `json:"winddirection"` // 风向
		Windpower     string `json:"windpower"`     // 风力（级）
		Humidity      string `json:"humidity"`      // 空气湿度（%）
		Reporttime    string `json:"reporttime"`    // 数据发布时间
	} `json:"lives"`
	Forecast []struct { // 预报天气数据（extensions=all时返回）
		Province   string     `json:"province"`   // 省份名
		City       string     `json:"city"`       // 城市名
		Adcode     string     `json:"adcode"`     // 区域编码
		Reporttime string     `json:"reporttime"` // 预报发布时间
		Casts      []struct { // 预报数据（当天、第二天、第三天）
			Date         string `json:"date"`         // 日期（YYYY-MM-DD）
			Week         string `json:"week"`         // 星期几
			Dayweather   string `json:"dayweather"`   // 白天天气
			Nightweather string `json:"nightweather"` // 夜间天气
			Daytemp      string `json:"daytemp"`      // 白天温度（℃）
			Nighttemp    string `json:"nighttemp"`    // 夜间温度（℃）
			Daywind      string `json:"daywind"`      // 白天风向
			Nightwind    string `json:"nightwind"`    // 夜间风向
			Daypower     string `json:"daypower"`     // 白天风力（级）
			Nightpower   string `json:"nightpower"`   // 夜间风力（级）
		} `json:"casts"`
	} `json:"forecast"`
}

// 通知类型定义（与路径规划工具保持一致）
const (
	NotificationTypeLoading = "loading"
	NotificationTypeResult  = "result"
	NotificationTypeError   = "error"
)

func WeatherServer() *server.StreamableHTTPServer {
	// 初始化配置
	if err := config.Init(""); err != nil {
		log.Fatalf("配置初始化失败：%v", err)
	}

	// 1. 初始化MCP Server
	mcpServer := server.NewMCPServer("AMap Weather Query", "1.0.0")

	// 2. 加载高德API Key（与路径规划工具共用Key）
	amapKey := os.Getenv("AMAP_WEB_API_KEY")
	if amapKey == "" {
		amapKey = config.Cfg.Amap.WebApiKey
	}
	if amapKey == "" {
		log.Fatalf("未配置高德地图Web API Key（环境变量AMAP_WEB_API_KEY或配置文件）")
	}

	// 3. 定义天气查询工具（参数严格遵循高德API要求）
	weatherTool := mcp.NewTool("query_weather",
		mcp.WithDescription("查询指定城市的天气信息，支持实况天气和未来3天预报"),
		mcp.WithString("adcode", mcp.Required(), mcp.Description("城市编码（adcode），可参考高德城市编码表，例：110101（北京东城区）、610101（西安新城区）")),
		mcp.WithString("extensions", mcp.Description("气象类型：base=实况天气（默认），all=未来3天预报+实况天气")),
		mcp.WithString("output", mcp.Description("返回格式：JSON（默认）、XML，建议使用JSON")),
	)

	// 4. 注册工具流式处理函数
	mcpServer.AddTool(weatherTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		// 获取当前会话
		session := server.ClientSessionFromContext(ctx)
		if session == nil {
			log.Printf("无法获取会话信息")
			return mcp.NewToolResultError("会话初始化失败"), nil
		}

		// 解析请求参数
		args, ok := request.Params.Arguments.(map[string]interface{})
		if !ok {
			errMsg := "参数格式错误：预期map[string]interface{}"
			sendStreamNotification(session, NotificationTypeError, errMsg)
			return mcp.NewToolResultError(errMsg), nil
		}

		// 提取并处理参数（设置默认值）
		adcode, ok1 := args["adcode"].(string)
		extensions := getStringParam(args, "extensions", "base") // 默认查询实况天气
		output := getStringParam(args, "output", "JSON")         // 默认JSON格式

		// 校验必填参数
		if !ok1 || adcode == "" {
			errMsg := "缺少必填参数：adcode（城市编码），请参考高德城市编码表获取"
			sendStreamNotification(session, NotificationTypeError, errMsg)
			return mcp.NewToolResultError(errMsg), nil
		}

		// 校验可选参数合法性
		if extensions != "base" && extensions != "all" {
			errMsg := fmt.Sprintf("无效的extensions参数：%s，仅支持base（实况）或all（预报）", extensions)
			sendStreamNotification(session, NotificationTypeError, errMsg)
			return mcp.NewToolResultError(errMsg), nil
		}
		if output != "JSON" && output != "XML" {
			errMsg := fmt.Sprintf("无效的output参数：%s，仅支持JSON或XML", output)
			sendStreamNotification(session, NotificationTypeError, errMsg)
			return mcp.NewToolResultError(errMsg), nil
		}

		// 发送加载状态通知
		loadingMsg := fmt.Sprintf(
			"正在查询城市编码【%s】的天气信息...\n查询类型：%s\n返回格式：%s",
			adcode, map[string]string{"base": "实况天气", "all": "实况+未来3天预报"}[extensions], output,
		)
		sendStreamNotification(session, NotificationTypeLoading, loadingMsg)

		// 模拟网络延迟（可选，提升流式体验）
		time.Sleep(200 * time.Millisecond)

		// 5. 调用高德天气API
		apiURL := fmt.Sprintf(
			"https://restapi.amap.com/v3/weather/weatherInfo?key=%s&city=%s&extensions=%s&output=%s",
			amapKey, adcode, extensions, output,
		)

		resp, err := http.Get(apiURL)
		if err != nil {
			errMsg := fmt.Sprintf("高德天气API调用失败：%v", err)
			sendStreamNotification(session, NotificationTypeError, errMsg)
			return mcp.NewToolResultError(errMsg), nil
		}
		defer func(Body io.ReadCloser) {
			if err := Body.Close(); err != nil {
				log.Printf("关闭API响应体失败：%v", err)
			}
		}(resp.Body)

		// 6. 解析API响应
		body, err := io.ReadAll(resp.Body)
		if err != nil {
			errMsg := fmt.Sprintf("读取API响应失败：%v", err)
			sendStreamNotification(session, NotificationTypeError, errMsg)
			return mcp.NewToolResultError(errMsg), nil
		}

		// 若请求XML格式，直接返回原始响应
		if output == "XML" {
			resultMsg := fmt.Sprintf("天气查询完成（XML格式）\n数据发布时间：%s\n原始响应：\n%s",
				time.Now().Format("2006-01-02 15:04:05"), string(body))
			sendStreamNotification(session, NotificationTypeResult, resultMsg)
			return mcp.NewToolResultText("天气查询完成，详细结果已通过流式通知返回"), nil
		}

		// JSON格式解析
		var weatherResp AmapWeatherResponse
		if err := json.Unmarshal(body, &weatherResp); err != nil {
			errMsg := fmt.Sprintf("解析JSON响应失败：%v（原始响应：%s）", err, string(body))
			sendStreamNotification(session, NotificationTypeError, errMsg)
			return mcp.NewToolResultError(errMsg), nil
		}

		// 7. 处理API响应状态
		if weatherResp.Status != "1" || weatherResp.Infocode != "10000" {
			errMsg := fmt.Sprintf(
				"天气查询失败\n状态码：%s\n错误信息：%s（%s）\n原始响应：%s",
				weatherResp.Status, weatherResp.Info, weatherResp.Infocode, string(body),
			)
			sendStreamNotification(session, NotificationTypeError, errMsg)
			return mcp.NewToolResultError(errMsg), nil
		}

		// 8. 格式化查询结果
		var finalResult string
		if len(weatherResp.Lives) > 0 {
			// 拼接实况天气信息
			live := weatherResp.Lives[0]
			finalResult += fmt.Sprintf(`
📊 【实况天气】
📍 区域信息：%s > %s（adcode：%s）
🌤️  天气状况：%s
🌡️  实时气温：%s ℃
💨  风向风力：%s %s 级
💧  空气湿度：%s %%
⏰  数据发布：%s`,
				live.Province, live.City, live.Adcode,
				live.Weather, live.Temperature,
				live.Winddirection, live.Windpower,
				live.Humidity, live.Reporttime,
			)
		}

		if extensions == "all" && len(weatherResp.Forecast) > 0 && len(weatherResp.Forecast[0].Casts) > 0 {
			// 拼接未来3天预报信息
			forecast := weatherResp.Forecast[0]
			finalResult += fmt.Sprintf(`

📅 【未来3天预报】
📢 预报发布时间：%s
`, forecast.Reporttime)

			for i, cast := range forecast.Casts {
				dayDesc := map[int]string{0: "今天", 1: "明天", 2: "后天"}[i]
				finalResult += fmt.Sprintf(`
%s（%s · %s）
🌞 白天：%s | 温度：%s ℃ | 风向：%s | 风力：%s 级
🌙 夜间：%s | 温度：%s ℃ | 风向：%s | 风力：%s 级
`,
					dayDesc, cast.Date, getWeekDay(cast.Week),
					cast.Dayweather, cast.Daytemp, cast.Daywind, cast.Daypower,
					cast.Nightweather, cast.Nighttemp, cast.Nightwind, cast.Nightpower,
				)
			}
		}

		// 发送最终结果通知
		sendStreamNotification(session, NotificationTypeResult, finalResult)

		return mcp.NewToolResultText("天气查询完成，详细结果已通过流式通知返回"), nil
	})

	// 9. 初始化StreamableHTTPServer（与路径规划工具共享端口时，需修改路由路径）
	return server.NewStreamableHTTPServer(mcpServer,
		server.WithStateful(true),
		server.WithHeartbeatInterval(30*time.Second),
	)
}

// 辅助函数：获取字符串参数，不存在时返回默认值
func getStringParam(args map[string]interface{}, key, defaultValue string) string {
	val, ok := args[key].(string)
	if !ok || val == "" {
		return defaultValue
	}
	return val
}

// 辅助函数：将数字星期转换为中文（1=周一，7=周日）
func getWeekDay(weekStr string) string {
	weekMap := map[string]string{
		"1": "周一", "2": "周二", "3": "周三",
		"4": "周四", "5": "周五", "6": "周六",
		"7": "周日",
	}
	if val, ok := weekMap[weekStr]; ok {
		return val
	}
	return weekStr
}

// 辅助函数：发送流式通知（复用路径规划工具的通知逻辑）
func sendStreamNotification(session server.ClientSession, notifyType, content string) {
	// 构建自定义参数（存入 AdditionalFields）
	additionalFields := map[string]any{
		"type":      notifyType,
		"content":   content,
		"timestamp": time.Now().Format("2006-01-02 15:04:05"),
	}

	// 构建 MCP 通知（适配结构体定义）
	notification := mcp.JSONRPCNotification{
		JSONRPC: "2.0",
		Notification: mcp.Notification{ // 显式指定嵌套结构体
			Method: "stream_notification", // 直接赋值 Method（嵌套字段提升）
			Params: mcp.NotificationParams{
				AdditionalFields: additionalFields, // 自定义参数存入此处
			},
		},
	}

	select {
	case session.NotificationChannel() <- notification:
		log.Printf("流式通知发送成功（类型：%s）", notifyType)
	default:
		log.Printf("流式通知发送失败：通道已满（类型：%s）", notifyType)
	}
}
